#include "StdAfx.hpp"
#include "ShaderConstants.hpp"
#include "Framework.hpp"
#include "Texture.hpp"
#include "ProgramMain.hpp"

using namespace common;


////////////////////////////////////////////////////////////////////////////////
// struct ShaderConstant

ShaderConstant::ShaderConstant(common::tokdoc::Node *node)
: Name(node->Name)
{
}


////////////////////////////////////////////////////////////////////////////////
// struct BoolShaderConstant

BoolShaderConstant::BoolShaderConstant(tokdoc::Node *node)
: ShaderConstant(node)
, Value(false)
{
	tokdoc::Node *valNode = node->FindFirstChild(EMPTY_STRING);
	bool ok = false;
	if (valNode)
		ok = tokdoc::NodeTo(Value, *valNode, false);
	if (!ok)
		LOG(LOG_APP | LOG_WARNING, "Cannot load bool shader constant \"" + Name + "\".");
}

bool BoolShaderConstant::SetInEffect(ID3DXEffect *eff, bool logWarning)
{
	HRESULT hr = eff->SetBool(Name.c_str(), Value ? TRUE : FALSE);
	if (SUCCEEDED(hr))
		return true;
	else
	{
		if (logWarning)
			LOG(LOG_APP | LOG_WARNING, "Cannot set bool shader constant \"" + Name + "\".");
		return false;
	}
}

////////////////////////////////////////////////////////////////////////////////
// struct IntShaderConstant

IntShaderConstant::IntShaderConstant(tokdoc::Node *node)
: ShaderConstant(node)
, Value(0)
{
	tokdoc::Node *valNode = node->FindFirstChild(EMPTY_STRING);
	bool ok = false;
	if (valNode)
		ok = tokdoc::NodeTo(Value, *valNode, false);
	if (!ok)
		LOG(LOG_APP | LOG_WARNING, "Cannot load int shader constant \"" + Name + "\".");
}

bool IntShaderConstant::SetInEffect(ID3DXEffect *eff, bool logWarning)
{
	HRESULT hr = eff->SetInt(Name.c_str(), Value);
	if (SUCCEEDED(hr))
		return true;
	else
	{
		if (logWarning)
			LOG(LOG_APP | LOG_WARNING, "Cannot set int shader constant \"" + Name + "\".");
		return false;
	}
}

////////////////////////////////////////////////////////////////////////////////
// struct FloatShaderConstant

FloatShaderConstant::FloatShaderConstant(tokdoc::Node *node)
: ShaderConstant(node)
, Value(0.f)
{
	tokdoc::Node *valNode = node->FindFirstChild(EMPTY_STRING);
	bool ok = false;
	if (valNode)
		ok = tokdoc::NodeTo(Value, *valNode, false);
	if (!ok)
		LOG(LOG_APP | LOG_WARNING, "Cannot load float shader constant \"" + Name + "\".");
}

bool FloatShaderConstant::SetInEffect(ID3DXEffect *eff, bool logWarning)
{
	HRESULT hr = eff->SetFloat(Name.c_str(), Value);
	if (SUCCEEDED(hr))
		return true;
	else
	{
		if (logWarning)
			LOG(LOG_APP | LOG_WARNING, "Cannot set float shader constant \"" + Name + "\".");
		return false;
	}
}

////////////////////////////////////////////////////////////////////////////////
// struct Float4ShaderConstant

Float4ShaderConstant::Float4ShaderConstant(tokdoc::Node *node)
: ShaderConstant(node)
, Value(VEC4_ZERO)
{
	bool ok = tokdoc::NodeTo(Value, *node, false);
	if (!ok)
		LOG(LOG_APP | LOG_WARNING, "Cannot load float4 shader constant \"" + Name + "\".");
}

bool Float4ShaderConstant::SetInEffect(ID3DXEffect *eff, bool logWarning)
{
	HRESULT hr = eff->SetVector(Name.c_str(), &Value);
	if (SUCCEEDED(hr))
		return true;
	else
	{
		if (logWarning)
			LOG(LOG_APP | LOG_WARNING, "Cannot set float4 shader constant \"" + Name + "\".");
		return false;
	}
}

////////////////////////////////////////////////////////////////////////////////
// struct Float4x4ShaderConstant

Float4x4ShaderConstant::Float4x4ShaderConstant(tokdoc::Node *node)
: ShaderConstant(node)
, Value(VEC4_ZERO)
{
	bool ok = tokdoc::NodeTo(Value, *node, false);
	if (!ok)
		LOG(LOG_APP | LOG_WARNING, "Cannot load float4x4 shader constant \"" + Name + "\".");
}

bool Float4x4ShaderConstant::SetInEffect(ID3DXEffect *eff, bool logWarning)
{
	HRESULT hr = eff->SetMatrix(Name.c_str(), &Value);
	if (SUCCEEDED(hr))
		return true;
	else
	{
		if (logWarning)
			LOG(LOG_APP | LOG_WARNING, "Cannot set float4x4 shader constant \"" + Name + "\".");
		return false;
	}
}

////////////////////////////////////////////////////////////////////////////////
// struct TextureShaderConstant

TextureShaderConstant::TextureShaderConstant(tokdoc::Node *node)
: ShaderConstant(node)
, Texture(NULL)
{
	string filePath;
	tokdoc::Node *filePathNode = node->FindFirstChild(EMPTY_STRING);
	if (filePathNode)
		filePath = filePathNode->Value;
	if (!filePath.empty())
	{
		string absPath;
		RelativeToAbsolutePath(&absPath, frame::DataDir, filePath);
		Texture = D3dTextureFromFile::GetOrCreate(filePath, absPath);
		if (Texture)
		{
			Texture->EnableFileChangeMonitoring(ResourceObject::STATE_LOADING);
			Texture->BeginLoading();
		}
	}
	else
		LOG(LOG_APP | LOG_WARNING, "File path for texture shader constant \"" + Name + "\" not specified.");
}

bool TextureShaderConstant::SetInEffect( ID3DXEffect *eff, bool logWarning )
{
	assert(eff);

	IDirect3DBaseTexture9 *texture;
	if (Texture && Texture->IsLoaded())
		texture = Texture->GetBaseTexture();
	else
		texture = GetEmptyDiffuseTexture();

	HRESULT hr = eff->SetTexture(Name.c_str(), texture);
	if (SUCCEEDED(hr))
		return true;
	else
	{
		if (logWarning)
			LOG(LOG_APP | LOG_WARNING, "Cannot set texture shader constant \"" + Name + "\".");
		return false;
	}
}

bool TextureShaderConstant::IsLoaded()
{
	return Texture && Texture->IsLoaded();
}
